RMarkdown Notebook visualization stack presenting coffee production over time, comparing retail and grower profit margins, and measuring grower revenue against national poverty lines
setwd("~/Desktop/Personal Projects/Coffee Data ")
#import packages
library(RColorBrewer)
library(dplyr)
Attaching package: ‘dplyr’
The following objects are masked from ‘package:stats’:
filter, lag
The following objects are masked from ‘package:base’:
intersect, setdiff, setequal, union
library(plotly)
Loading required package: ggplot2
Want to understand how all the pieces fit together? Read R for Data Science:
https://r4ds.had.co.nz/
Registered S3 method overwritten by 'data.table':
method from
print.data.table
Registered S3 methods overwritten by 'htmltools':
method from
print.html tools:rstudio
print.shiny.tag tools:rstudio
print.shiny.tag.list tools:rstudio
Registered S3 method overwritten by 'htmlwidgets':
method from
print.htmlwidget tools:rstudio
Attaching package: ‘plotly’
The following object is masked from ‘package:ggplot2’:
last_plot
The following object is masked from ‘package:stats’:
filter
The following object is masked from ‘package:graphics’:
layout
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
method from
print.tbl_lazy
print.tbl_sql
── Attaching packages ────────────────────────────────────────────────────────────────────── tidyverse 1.3.1 ──
✓ tibble 3.1.4 ✓ purrr 0.3.4
✓ tidyr 1.1.3 ✓ stringr 1.4.0
✓ readr 2.0.1 ✓ forcats 0.5.1
── Conflicts ───────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
x plotly::filter() masks dplyr::filter(), stats::filter()
x dplyr::lag() masks stats::lag()
library(gridExtra)
Attaching package: ‘gridExtra’
The following object is masked from ‘package:dplyr’:
combine
library(ggplot2)
library(readxl)
library(waterfall)
Loading required package: lattice
Prepare Data
#import data files
total_production = read.csv(file = 'total-production.csv')
retail_prices = read.csv(file = 'retail-prices.csv')
grower_compensation = read.csv(file = 'prices-paid-to-growers.csv')
exports_number = read.csv(file = 'exports-crop-year.csv')
poverty_lines = read.csv(file = 'national-poverty-lines-vs-gdp-per-capita.csv')
coffee_consumption = read.csv(file = 'disappearance.csv')
#rename columns
colnames(retail_prices)[which(names(retail_prices) == 'retail_prices')] = 'country'
#subset columns from poverty lines
poverty_lines = data.frame(subset(poverty_lines, select = c(National.poverty.lines..Jolliffe.and.Prydz..2016..,Entity,Year)))
#remove NAs
poverty_lines = na.omit(poverty_lines)
Visualizing total producion over the years
#transpose total production df
total_production_2 = data.frame(t(total_production))
#create function to take first row as column names
header.true <- function(df) {
names(df) <- as.character(unlist(df[1,]))
df[-1,]
}
total_production_2 = header.true(total_production_2)
#create a column of years from 1990-2018
years = seq(1990,2018)
total_production_2 <- tibble::rownames_to_column(total_production_2, "Year")
total_production_2["Year"] = c(years)
#Plot first 6 countries
#create list of plots
plot_list = list()
#create 6 plots, add to list of plots
for (i in 2:7) {
total_production_2[,i] = sapply(total_production_2[,i], as.numeric)
p = ggplot(data = total_production_2,aes_string(x = "Year", y = as.name((colnames(total_production_2[i]))))) + geom_point(stat = "identity")
plot_list[[i]] = p
}
#drop first plot
plot_list = plot_list[-1]
#show plot list
do.call(grid.arrange, list(grobs = plot_list, ncol=3))

Compare grower vs retail profit margin
# Prepare data
production_costs = read_excel("Coffee Production Costs.xlsx")
New names:
* `` -> ...1
production_costs = data.frame(t(production_costs))
production_costs = subset(production_costs, select = c(X7))
production_costs['country'] = rownames(production_costs)
production_costs = production_costs[-1,]
production_costs['Production Costs'] = production_costs['X7'] #assign production cost column
# Aggregate data
colnames(grower_compensation)[which(names(grower_compensation) == 'prices_paid_to_growers')] = 'country' #rename country column
costs_compensation = data.frame(inner_join(production_costs, grower_compensation)) #take overlap between porouduction cost and grower compensation
Joining, by = "country"
costs_compensation = data.frame((subset(costs_compensation, select = (-c(X7)))))
A = function(x) x * 0.45359237 #From 1 pound to 1 kg
costs_compensation['Production.Costs'] = sapply(costs_compensation['Production.Costs'], as.numeric)
x = as.numeric(colMeans(costs_compensation['Production.Costs']))
costs_compensation['Production.Costs'] = apply(costs_compensation['Production.Costs'],2, A)
#function to calculate profit margin
profit_margin = function(price, consumption, cost, production) {
(((price * consumption) - (cost*production)) / (price * consumption))
}
#function to calculate average over the years
average = function(dataframe, a){
dataframe = dataframe[-1]
avg_data = colMeans(dataframe, na.rm=TRUE)
avg_data = data.frame(t(data.frame(avg_data)))
rownames(avg_data) = a
return (avg_data)
}
#calculate profit margin for retail side
average_retail_price = average(retail_prices, "average_retail_price")
average_coffee_consumption = average(coffee_consumption, "average_coffee_consumption")
average_coffee_consumption[1,] = average_coffee_consumption[1,]*60*1000 #multiply by 60-kg thousand bags
average_coffee_trade_price = average(grower_compensation, "average_coffee_trade_price")
average_exports = average(exports_number, "total_exports")
average_exports[1,] = average_exports[1,] * 60 *1000 #multiply by 60-kg thousand bags
#average retail export-price-consumption df
retail_price_consumption = rbind(average_retail_price, average_coffee_consumption,average_coffee_trade_price, average_exports)
retail_price_consumption = data.frame(t(retail_price_consumption)) #transpose
#calculate retail revenue
retail_price_consumption$revenue = 0
retail_price_consumption$revenue = retail_price_consumption$average_retail_price * retail_price_consumption$average_coffee_consumption
#calculate retail costs
retail_price_consumption$cost = 0
retail_price_consumption$cost = retail_price_consumption$average_coffee_trade_price*retail_price_consumption$total_exports
#caclculate profit margin
retail_price_consumption$profit_margin = 0
retail_price_consumption$profit_margin = mapply(profit_margin, retail_price_consumption$average_retail_price,retail_price_consumption$average_coffee_consumption, retail_price_consumption$average_coffee_trade_price,retail_price_consumption$total_exports)
#create years column
years = seq(1990,2018)
retail_price_consumption <- tibble::rownames_to_column(retail_price_consumption, "Year")
retail_price_consumption["Year"] = c(years)
#Calculate profit margin for grower side
#average production of coffee
average_production = average(total_production, "average_production")
average_production[1,] = average_production[1,]*60*1000
#grower price - exports - production
grower_price_consumption = rbind(average_coffee_trade_price,average_exports, average_production)
grower_price_consumption = data.frame(t(grower_price_consumption))
#grower production cost/lkg
grower_price_consumption$production_costs = 1
grower_price_consumption$production_costs = grower_price_consumption$production_costs * as.numeric(colMeans(costs_compensation['Production.Costs']))
#grower revenue
grower_price_consumption$revenue = 0
grower_price_consumption$revenue = grower_price_consumption$average_coffee_trade_price*grower_price_consumption$total_exports
#grower costs
grower_price_consumption$cost = 0
grower_price_consumption$cost = grower_price_consumption$production_costs*grower_price_consumption$average_production
#grower profit margin
grower_price_consumption$profit_margin = 0
grower_price_consumption$profit_margin = mapply(profit_margin, grower_price_consumption$average_coffee_trade_price,grower_price_consumption$total_exports, grower_price_consumption$production_costs,grower_price_consumption$average_production)
#create years column
grower_price_consumption <- tibble::rownames_to_column(grower_price_consumption, "Year")
grower_price_consumption["Year"] = c(years)
Bar chart: revenue - cost - profit margin for both in each year . vertical 3 part + margin percent
#barplot as matrix profit margin , revenue between the two
profit_margin = data.frame(cbind(grower_price_consumption$Year, grower_price_consumption$profit_margin, retail_price_consumption$profit_margin))
colnames(profit_margin)[which(names(profit_margin) == 'X1')] = 'Year'
colnames(profit_margin)[which(names(profit_margin) == 'X2')] = 'Grower Profit Margin'
colnames(profit_margin)[which(names(profit_margin) == 'X3')] = 'Retail Profit Margin'
profit_margin = data.frame(t(profit_margin))
profit_margin = header.true(profit_margin)
barplot(height = as.matrix(profit_margin), las=2, cex.names = 0.9, col = c("chartreuse4","cadetblue3"), beside = TRUE, legend=TRUE, ylim = c(0,1.5))
revenue = data.frame(cbind(grower_price_consumption$Year, grower_price_consumption$revenue, retail_price_consumption$revenue))
colnames(revenue)[which(names(revenue) == 'X1')] = 'Year'
colnames(revenue)[which(names(revenue) == 'X2')] = 'Grower Revenue'
colnames(revenue)[which(names(revenue) == 'X3')] = 'Retail Revenue'
revenue = data.frame(t(revenue))
revenue = header.true(revenue)
opar = par(oma = c(1,0,0,8))

barplot(height = as.matrix(revenue),las=2, cex.names = 0.5, cex.axis = 0.5, col = c("chartreuse4","cadetblue3"), beside = TRUE, yaxp=c(0, max(revenue), 5))
par(opar)
opar = par(oma = c(0,0,0,0), mar = c(0,0,0,0), new = TRUE)
legend(x = "right", legend = rownames(revenue), fill = c("chartreuse4","cadetblue3"), bty = "n", y.intersp = 2)
par(opar) # Reset par

NA
NA
NA
Plot farmer profits/kg of coffee to the poeverty lỉne (USD/day) for each country
# Prepare data
colnames(poverty_lines)[which(names(poverty_lines) == 'Entity')] = 'country'
costs_compen_country = data.frame(inner_join(costs_compensation,poverty_lines))
Joining, by = "country"
costs_compen_country['Profits'] =costs_compen_country$X2011 - costs_compen_country$Production.Costs
colnames(costs_compen_country)[which(names(costs_compen_country) == 'National.poverty.lines..Jolliffe.and.Prydz..2016..')] = 'Poverty Lines'
# Plot
fig <- plot_ly()
fig <- fig %>%
add_trace(
type = "indicator",
mode = "number+gauge",
value = as.numeric(subset(subset(costs_compen_country, country == 'Colombia'),select = c(Profits))),
domain = list(x = c(0.25, 1), y = c(0.4, 0.6)),
title = list(text = 'Colombia'),
gauge = list(
shape = "bullet",
axis = list(range = list(NULL, 6)),
threshold = list(
line = list(color = "red", width = 2),
thickness = 0.75,
value = as.numeric(subset(costs_compen_country, country == 'Colombia')['Poverty Lines'])),
steps = list(
list(range = c(0,0.5), color = "white"),
list(range = c(0.5,2), color = "white"))),
bar = list(color = "black"))
fig <- fig %>%
add_trace(
type = "indicator",
mode = "number+gauge",
value = as.numeric(subset(subset(costs_compen_country, country == 'Guatemala'),select = c(Profits))),
domain = list(x = c(0.25, 1), y = c(0.7, 0.9)),
title = list(text = 'Guatemala'),
gauge = list(
shape = "bullet",
axis = list(range = list(NULL, 6)),
threshold = list(
line = list(color = "red", width = 2),
thickness = 0.75,
value = as.numeric(subset(costs_compen_country, country == 'Guatemala')['Poverty Lines'])),
steps = list(
list(range = c(0,0.5), color = "white"),
list(range = c(0.5,2), color = "white"))),
bar = list(color = "black"))
fig <- fig %>%
add_trace(
type = "indicator",
mode = "number+gauge",
value = as.numeric(subset(subset(costs_compen_country, country == 'El Salvador'),select = c(Profits))),
domain = list(x = c(0.25, 1), y = c(0.08, 0.25)),
title = list(text = 'El Salvador'),
gauge = list(
shape = "bullet",
axis = list(range = list(NULL, 6)),
threshold = list(
line = list(color = "red", width = 2),
thickness = 0.75,
value = as.numeric(subset(costs_compen_country, country == 'El Salvador')['Poverty Lines'])),
steps = list(
list(range = c(0,0.5), color = "white"),
list(range = c(0.5,2), color = "white"))),
bar = list(color = "black"))
fig
NA
LS0tCnRpdGxlOiAiVmlzdWFsaXppbmcgQ29mZmVlIFRyYWRlIGRhdGEiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KClJNYXJrZG93biBOb3RlYm9vayB2aXN1YWxpemF0aW9uIHN0YWNrIHByZXNlbnRpbmcgY29mZmVlIHByb2R1Y3Rpb24gb3ZlciB0aW1lLCBjb21wYXJpbmcgcmV0YWlsIGFuZCBncm93ZXIgcHJvZml0IG1hcmdpbnMsIGFuZCBtZWFzdXJpbmcgZ3Jvd2VyIHJldmVudWUgYWdhaW5zdCBuYXRpb25hbCBwb3ZlcnR5IGxpbmVzCgpgYGB7cn0Kc2V0d2QoIn4vRGVza3RvcC9QZXJzb25hbCBQcm9qZWN0cy9Db2ZmZWUgRGF0YSAiKQojaW1wb3J0IHBhY2thZ2VzIApsaWJyYXJ5KFJDb2xvckJyZXdlcikKbGlicmFyeShkcGx5cikKbGlicmFyeShwbG90bHkpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeSh3YXRlcmZhbGwpCgpgYGAKCiMjIyBQcmVwYXJlIERhdGEKCmBgYHtyfQojaW1wb3J0IGRhdGEgZmlsZXMgCnRvdGFsX3Byb2R1Y3Rpb24gPSByZWFkLmNzdihmaWxlID0gJ3RvdGFsLXByb2R1Y3Rpb24uY3N2JykKcmV0YWlsX3ByaWNlcyA9IHJlYWQuY3N2KGZpbGUgPSAncmV0YWlsLXByaWNlcy5jc3YnKQpncm93ZXJfY29tcGVuc2F0aW9uID0gcmVhZC5jc3YoZmlsZSA9ICdwcmljZXMtcGFpZC10by1ncm93ZXJzLmNzdicpIApleHBvcnRzX251bWJlciA9IHJlYWQuY3N2KGZpbGUgPSAnZXhwb3J0cy1jcm9wLXllYXIuY3N2JykKcG92ZXJ0eV9saW5lcyA9IHJlYWQuY3N2KGZpbGUgPSAnbmF0aW9uYWwtcG92ZXJ0eS1saW5lcy12cy1nZHAtcGVyLWNhcGl0YS5jc3YnKQpjb2ZmZWVfY29uc3VtcHRpb24gPSByZWFkLmNzdihmaWxlID0gJ2Rpc2FwcGVhcmFuY2UuY3N2JykKI3JlbmFtZSBjb2x1bW5zCmNvbG5hbWVzKHJldGFpbF9wcmljZXMpW3doaWNoKG5hbWVzKHJldGFpbF9wcmljZXMpID09ICdyZXRhaWxfcHJpY2VzJyldID0gJ2NvdW50cnknCiNzdWJzZXQgY29sdW1ucyBmcm9tIHBvdmVydHkgbGluZXMKcG92ZXJ0eV9saW5lcyA9IGRhdGEuZnJhbWUoc3Vic2V0KHBvdmVydHlfbGluZXMsIHNlbGVjdCA9IGMoTmF0aW9uYWwucG92ZXJ0eS5saW5lcy4uSm9sbGlmZmUuYW5kLlByeWR6Li4yMDE2Li4sRW50aXR5LFllYXIpKSkgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAojcmVtb3ZlIE5BcyAKcG92ZXJ0eV9saW5lcyA9IG5hLm9taXQocG92ZXJ0eV9saW5lcykgCmBgYAoKIyMjIFZpc3VhbGl6aW5nIHRvdGFsIHByb2R1Y2lvbiBvdmVyIHRoZSB5ZWFycwpgYGB7cn0KI3RyYW5zcG9zZSB0b3RhbCBwcm9kdWN0aW9uIGRmCnRvdGFsX3Byb2R1Y3Rpb25fMiA9IGRhdGEuZnJhbWUodCh0b3RhbF9wcm9kdWN0aW9uKSkKI2NyZWF0ZSBmdW5jdGlvbiB0byB0YWtlIGZpcnN0IHJvdyBhcyBjb2x1bW4gbmFtZXMKaGVhZGVyLnRydWUgPC0gZnVuY3Rpb24oZGYpIHsKICBuYW1lcyhkZikgPC0gYXMuY2hhcmFjdGVyKHVubGlzdChkZlsxLF0pKQogIGRmWy0xLF0KfQp0b3RhbF9wcm9kdWN0aW9uXzIgPSBoZWFkZXIudHJ1ZSh0b3RhbF9wcm9kdWN0aW9uXzIpCiNjcmVhdGUgYSBjb2x1bW4gb2YgeWVhcnMgZnJvbSAxOTkwLTIwMTgKeWVhcnMgPSBzZXEoMTk5MCwyMDE4KQp0b3RhbF9wcm9kdWN0aW9uXzIgPC0gdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4odG90YWxfcHJvZHVjdGlvbl8yLCAiWWVhciIpCnRvdGFsX3Byb2R1Y3Rpb25fMlsiWWVhciJdID0gYyh5ZWFycykKYGBgCgoKYGBge3J9CiNQbG90IGZpcnN0IDYgY291bnRyaWVzCiNjcmVhdGUgbGlzdCBvZiBwbG90cyAKcGxvdF9saXN0ID0gbGlzdCgpCiNjcmVhdGUgNiBwbG90cywgYWRkIHRvIGxpc3Qgb2YgcGxvdHMKZm9yIChpIGluIDI6NykgewogIHRvdGFsX3Byb2R1Y3Rpb25fMlssaV0gPSBzYXBwbHkodG90YWxfcHJvZHVjdGlvbl8yWyxpXSwgYXMubnVtZXJpYykKICBwID0gZ2dwbG90KGRhdGEgPSB0b3RhbF9wcm9kdWN0aW9uXzIsYWVzX3N0cmluZyh4ID0gIlllYXIiLCB5ID0gIGFzLm5hbWUoKGNvbG5hbWVzKHRvdGFsX3Byb2R1Y3Rpb25fMltpXSkpKSkpICsgZ2VvbV9wb2ludChzdGF0ID0gImlkZW50aXR5IikgCiAgcGxvdF9saXN0W1tpXV0gPSBwCn0KI2Ryb3AgZmlyc3QgcGxvdApwbG90X2xpc3QgPSBwbG90X2xpc3RbLTFdCiNzaG93IHBsb3QgbGlzdApkby5jYWxsKGdyaWQuYXJyYW5nZSwgbGlzdChncm9icyA9IHBsb3RfbGlzdCwgbmNvbD0zKSkKYGBgCgojIyMgQ29tcGFyZSBncm93ZXIgdnMgcmV0YWlsIHByb2ZpdCBtYXJnaW4gIApgYGB7cn0KIyBQcmVwYXJlIGRhdGEKcHJvZHVjdGlvbl9jb3N0cyA9IHJlYWRfZXhjZWwoIkNvZmZlZSBQcm9kdWN0aW9uIENvc3RzLnhsc3giKQpwcm9kdWN0aW9uX2Nvc3RzID0gZGF0YS5mcmFtZSh0KHByb2R1Y3Rpb25fY29zdHMpKQpwcm9kdWN0aW9uX2Nvc3RzID0gc3Vic2V0KHByb2R1Y3Rpb25fY29zdHMsIHNlbGVjdCA9IGMoWDcpKQpwcm9kdWN0aW9uX2Nvc3RzWydjb3VudHJ5J10gPSByb3duYW1lcyhwcm9kdWN0aW9uX2Nvc3RzKQpwcm9kdWN0aW9uX2Nvc3RzID0gcHJvZHVjdGlvbl9jb3N0c1stMSxdCnByb2R1Y3Rpb25fY29zdHNbJ1Byb2R1Y3Rpb24gQ29zdHMnXSA9IHByb2R1Y3Rpb25fY29zdHNbJ1g3J10gI2Fzc2lnbiBwcm9kdWN0aW9uIGNvc3QgY29sdW1uCgojIEFnZ3JlZ2F0ZSBkYXRhCmNvbG5hbWVzKGdyb3dlcl9jb21wZW5zYXRpb24pW3doaWNoKG5hbWVzKGdyb3dlcl9jb21wZW5zYXRpb24pID09ICdwcmljZXNfcGFpZF90b19ncm93ZXJzJyldID0gJ2NvdW50cnknICNyZW5hbWUgY291bnRyeSBjb2x1bW4KY29zdHNfY29tcGVuc2F0aW9uID0gZGF0YS5mcmFtZShpbm5lcl9qb2luKHByb2R1Y3Rpb25fY29zdHMsIGdyb3dlcl9jb21wZW5zYXRpb24pKSAjdGFrZSBvdmVybGFwIGJldHdlZW4gcG9yb3VkdWN0aW9uIGNvc3QgYW5kIGdyb3dlciBjb21wZW5zYXRpb24gCmNvc3RzX2NvbXBlbnNhdGlvbiA9IGRhdGEuZnJhbWUoKHN1YnNldChjb3N0c19jb21wZW5zYXRpb24sIHNlbGVjdCA9ICgtYyhYNykpKSkpCkEgPSBmdW5jdGlvbih4KSB4ICogMC40NTM1OTIzNyAjRnJvbSAxIHBvdW5kIHRvIDEga2cgCmNvc3RzX2NvbXBlbnNhdGlvblsnUHJvZHVjdGlvbi5Db3N0cyddID0gc2FwcGx5KGNvc3RzX2NvbXBlbnNhdGlvblsnUHJvZHVjdGlvbi5Db3N0cyddLCBhcy5udW1lcmljKQp4ID0gYXMubnVtZXJpYyhjb2xNZWFucyhjb3N0c19jb21wZW5zYXRpb25bJ1Byb2R1Y3Rpb24uQ29zdHMnXSkpCmNvc3RzX2NvbXBlbnNhdGlvblsnUHJvZHVjdGlvbi5Db3N0cyddID0gYXBwbHkoY29zdHNfY29tcGVuc2F0aW9uWydQcm9kdWN0aW9uLkNvc3RzJ10sMiwgQSkKYGBgCgpgYGB7cn0KI2Z1bmN0aW9uIHRvIGNhbGN1bGF0ZSBwcm9maXQgbWFyZ2luIApwcm9maXRfbWFyZ2luID0gZnVuY3Rpb24ocHJpY2UsIGNvbnN1bXB0aW9uLCBjb3N0LCBwcm9kdWN0aW9uKSB7CiAgKCgocHJpY2UgKiBjb25zdW1wdGlvbikgLSAoY29zdCpwcm9kdWN0aW9uKSkgLyAgKHByaWNlICogY29uc3VtcHRpb24pKSAKfQojZnVuY3Rpb24gdG8gY2FsY3VsYXRlIGF2ZXJhZ2Ugb3ZlciB0aGUgeWVhcnMKYXZlcmFnZSA9IGZ1bmN0aW9uKGRhdGFmcmFtZSwgYSl7CiBkYXRhZnJhbWUgPSBkYXRhZnJhbWVbLTFdCiBhdmdfZGF0YSA9IGNvbE1lYW5zKGRhdGFmcmFtZSwgbmEucm09VFJVRSkKIGF2Z19kYXRhID0gZGF0YS5mcmFtZSh0KGRhdGEuZnJhbWUoYXZnX2RhdGEpKSkKIHJvd25hbWVzKGF2Z19kYXRhKSA9IGEKIHJldHVybiAoYXZnX2RhdGEpCn0KI2NhbGN1bGF0ZSBwcm9maXQgbWFyZ2luIGZvciByZXRhaWwgc2lkZSAKCmF2ZXJhZ2VfcmV0YWlsX3ByaWNlID0gYXZlcmFnZShyZXRhaWxfcHJpY2VzLCAiYXZlcmFnZV9yZXRhaWxfcHJpY2UiKQphdmVyYWdlX2NvZmZlZV9jb25zdW1wdGlvbiA9IGF2ZXJhZ2UoY29mZmVlX2NvbnN1bXB0aW9uLCAiYXZlcmFnZV9jb2ZmZWVfY29uc3VtcHRpb24iKQphdmVyYWdlX2NvZmZlZV9jb25zdW1wdGlvblsxLF0gPSBhdmVyYWdlX2NvZmZlZV9jb25zdW1wdGlvblsxLF0qNjAqMTAwMCAjbXVsdGlwbHkgYnkgNjAta2cgdGhvdXNhbmQgYmFncyAKYXZlcmFnZV9jb2ZmZWVfdHJhZGVfcHJpY2UgPSBhdmVyYWdlKGdyb3dlcl9jb21wZW5zYXRpb24sICJhdmVyYWdlX2NvZmZlZV90cmFkZV9wcmljZSIpCmF2ZXJhZ2VfZXhwb3J0cyA9IGF2ZXJhZ2UoZXhwb3J0c19udW1iZXIsICJ0b3RhbF9leHBvcnRzIikKYXZlcmFnZV9leHBvcnRzWzEsXSA9IGF2ZXJhZ2VfZXhwb3J0c1sxLF0gKiA2MCAqMTAwMCAjbXVsdGlwbHkgYnkgNjAta2cgdGhvdXNhbmQgYmFncyAKI2F2ZXJhZ2UgcmV0YWlsIGV4cG9ydC1wcmljZS1jb25zdW1wdGlvbiBkZgpyZXRhaWxfcHJpY2VfY29uc3VtcHRpb24gPSByYmluZChhdmVyYWdlX3JldGFpbF9wcmljZSwgYXZlcmFnZV9jb2ZmZWVfY29uc3VtcHRpb24sYXZlcmFnZV9jb2ZmZWVfdHJhZGVfcHJpY2UsIGF2ZXJhZ2VfZXhwb3J0cykKcmV0YWlsX3ByaWNlX2NvbnN1bXB0aW9uID0gZGF0YS5mcmFtZSh0KHJldGFpbF9wcmljZV9jb25zdW1wdGlvbikpICN0cmFuc3Bvc2UKI2NhbGN1bGF0ZSByZXRhaWwgcmV2ZW51ZSAKcmV0YWlsX3ByaWNlX2NvbnN1bXB0aW9uJHJldmVudWUgPSAwIApyZXRhaWxfcHJpY2VfY29uc3VtcHRpb24kcmV2ZW51ZSA9IHJldGFpbF9wcmljZV9jb25zdW1wdGlvbiRhdmVyYWdlX3JldGFpbF9wcmljZSAqIHJldGFpbF9wcmljZV9jb25zdW1wdGlvbiRhdmVyYWdlX2NvZmZlZV9jb25zdW1wdGlvbgojY2FsY3VsYXRlIHJldGFpbCBjb3N0cwpyZXRhaWxfcHJpY2VfY29uc3VtcHRpb24kY29zdCA9IDAgCnJldGFpbF9wcmljZV9jb25zdW1wdGlvbiRjb3N0ID0gcmV0YWlsX3ByaWNlX2NvbnN1bXB0aW9uJGF2ZXJhZ2VfY29mZmVlX3RyYWRlX3ByaWNlKnJldGFpbF9wcmljZV9jb25zdW1wdGlvbiR0b3RhbF9leHBvcnRzCiNjYWNsY3VsYXRlIHByb2ZpdCBtYXJnaW4gCnJldGFpbF9wcmljZV9jb25zdW1wdGlvbiRwcm9maXRfbWFyZ2luID0gMCAKcmV0YWlsX3ByaWNlX2NvbnN1bXB0aW9uJHByb2ZpdF9tYXJnaW4gPSBtYXBwbHkocHJvZml0X21hcmdpbiwgcmV0YWlsX3ByaWNlX2NvbnN1bXB0aW9uJGF2ZXJhZ2VfcmV0YWlsX3ByaWNlLHJldGFpbF9wcmljZV9jb25zdW1wdGlvbiRhdmVyYWdlX2NvZmZlZV9jb25zdW1wdGlvbiwgcmV0YWlsX3ByaWNlX2NvbnN1bXB0aW9uJGF2ZXJhZ2VfY29mZmVlX3RyYWRlX3ByaWNlLHJldGFpbF9wcmljZV9jb25zdW1wdGlvbiR0b3RhbF9leHBvcnRzKQojY3JlYXRlIHllYXJzIGNvbHVtbiAKeWVhcnMgPSBzZXEoMTk5MCwyMDE4KQpyZXRhaWxfcHJpY2VfY29uc3VtcHRpb24gPC0gdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4ocmV0YWlsX3ByaWNlX2NvbnN1bXB0aW9uLCAiWWVhciIpCnJldGFpbF9wcmljZV9jb25zdW1wdGlvblsiWWVhciJdID0gYyh5ZWFycykKYGBgCgoKYGBge3J9CiNDYWxjdWxhdGUgcHJvZml0IG1hcmdpbiBmb3IgZ3Jvd2VyIHNpZGUgCiNhdmVyYWdlIHByb2R1Y3Rpb24gb2YgY29mZmVlCmF2ZXJhZ2VfcHJvZHVjdGlvbiA9IGF2ZXJhZ2UodG90YWxfcHJvZHVjdGlvbiwgImF2ZXJhZ2VfcHJvZHVjdGlvbiIpCmF2ZXJhZ2VfcHJvZHVjdGlvblsxLF0gPSBhdmVyYWdlX3Byb2R1Y3Rpb25bMSxdKjYwKjEwMDAKI2dyb3dlciBwcmljZSAtIGV4cG9ydHMgLSBwcm9kdWN0aW9uIApncm93ZXJfcHJpY2VfY29uc3VtcHRpb24gPSByYmluZChhdmVyYWdlX2NvZmZlZV90cmFkZV9wcmljZSxhdmVyYWdlX2V4cG9ydHMsIGF2ZXJhZ2VfcHJvZHVjdGlvbikKZ3Jvd2VyX3ByaWNlX2NvbnN1bXB0aW9uID0gZGF0YS5mcmFtZSh0KGdyb3dlcl9wcmljZV9jb25zdW1wdGlvbikpCiNncm93ZXIgcHJvZHVjdGlvbiBjb3N0L2xrZyAKZ3Jvd2VyX3ByaWNlX2NvbnN1bXB0aW9uJHByb2R1Y3Rpb25fY29zdHMgPSAxCmdyb3dlcl9wcmljZV9jb25zdW1wdGlvbiRwcm9kdWN0aW9uX2Nvc3RzID0gZ3Jvd2VyX3ByaWNlX2NvbnN1bXB0aW9uJHByb2R1Y3Rpb25fY29zdHMgKiBhcy5udW1lcmljKGNvbE1lYW5zKGNvc3RzX2NvbXBlbnNhdGlvblsnUHJvZHVjdGlvbi5Db3N0cyddKSkKI2dyb3dlciByZXZlbnVlIApncm93ZXJfcHJpY2VfY29uc3VtcHRpb24kcmV2ZW51ZSA9IDAgCmdyb3dlcl9wcmljZV9jb25zdW1wdGlvbiRyZXZlbnVlID0gZ3Jvd2VyX3ByaWNlX2NvbnN1bXB0aW9uJGF2ZXJhZ2VfY29mZmVlX3RyYWRlX3ByaWNlKmdyb3dlcl9wcmljZV9jb25zdW1wdGlvbiR0b3RhbF9leHBvcnRzCiNncm93ZXIgY29zdHMgCmdyb3dlcl9wcmljZV9jb25zdW1wdGlvbiRjb3N0ID0gMCAKZ3Jvd2VyX3ByaWNlX2NvbnN1bXB0aW9uJGNvc3QgPSBncm93ZXJfcHJpY2VfY29uc3VtcHRpb24kcHJvZHVjdGlvbl9jb3N0cypncm93ZXJfcHJpY2VfY29uc3VtcHRpb24kYXZlcmFnZV9wcm9kdWN0aW9uIAojZ3Jvd2VyIHByb2ZpdCBtYXJnaW4gCmdyb3dlcl9wcmljZV9jb25zdW1wdGlvbiRwcm9maXRfbWFyZ2luID0gMCAKZ3Jvd2VyX3ByaWNlX2NvbnN1bXB0aW9uJHByb2ZpdF9tYXJnaW4gPSBtYXBwbHkocHJvZml0X21hcmdpbiwgZ3Jvd2VyX3ByaWNlX2NvbnN1bXB0aW9uJGF2ZXJhZ2VfY29mZmVlX3RyYWRlX3ByaWNlLGdyb3dlcl9wcmljZV9jb25zdW1wdGlvbiR0b3RhbF9leHBvcnRzLCBncm93ZXJfcHJpY2VfY29uc3VtcHRpb24kcHJvZHVjdGlvbl9jb3N0cyxncm93ZXJfcHJpY2VfY29uc3VtcHRpb24kYXZlcmFnZV9wcm9kdWN0aW9uKQoKI2NyZWF0ZSB5ZWFycyBjb2x1bW4gCmdyb3dlcl9wcmljZV9jb25zdW1wdGlvbiA8LSB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbihncm93ZXJfcHJpY2VfY29uc3VtcHRpb24sICJZZWFyIikKZ3Jvd2VyX3ByaWNlX2NvbnN1bXB0aW9uWyJZZWFyIl0gPSBjKHllYXJzKQpgYGAKIyMjIyBCYXIgY2hhcnQ6IHJldmVudWUgLSBjb3N0IC0gcHJvZml0IG1hcmdpbiBmb3IgYm90aCBpbiBlYWNoIHllYXIgLiB2ZXJ0aWNhbCAzIHBhcnQgKyBtYXJnaW4gcGVyY2VudApgYGB7cn0KI2JhcnBsb3QgYXMgbWF0cml4IHByb2ZpdCBtYXJnaW4gLCByZXZlbnVlIGJldHdlZW4gdGhlIHR3byAKCnByb2ZpdF9tYXJnaW4gPSBkYXRhLmZyYW1lKGNiaW5kKGdyb3dlcl9wcmljZV9jb25zdW1wdGlvbiRZZWFyLCBncm93ZXJfcHJpY2VfY29uc3VtcHRpb24kcHJvZml0X21hcmdpbiwgcmV0YWlsX3ByaWNlX2NvbnN1bXB0aW9uJHByb2ZpdF9tYXJnaW4pKQpjb2xuYW1lcyhwcm9maXRfbWFyZ2luKVt3aGljaChuYW1lcyhwcm9maXRfbWFyZ2luKSA9PSAnWDEnKV0gPSAnWWVhcicKY29sbmFtZXMocHJvZml0X21hcmdpbilbd2hpY2gobmFtZXMocHJvZml0X21hcmdpbikgPT0gJ1gyJyldID0gJ0dyb3dlciBQcm9maXQgTWFyZ2luJwpjb2xuYW1lcyhwcm9maXRfbWFyZ2luKVt3aGljaChuYW1lcyhwcm9maXRfbWFyZ2luKSA9PSAnWDMnKV0gPSAnUmV0YWlsIFByb2ZpdCBNYXJnaW4nCnByb2ZpdF9tYXJnaW4gPSBkYXRhLmZyYW1lKHQocHJvZml0X21hcmdpbikpCnByb2ZpdF9tYXJnaW4gPSBoZWFkZXIudHJ1ZShwcm9maXRfbWFyZ2luKQpiYXJwbG90KGhlaWdodCA9IGFzLm1hdHJpeChwcm9maXRfbWFyZ2luKSwgbGFzPTIsIGNleC5uYW1lcyA9IDAuOSwgY29sID0gYygiY2hhcnRyZXVzZTQiLCJjYWRldGJsdWUzIiksIGJlc2lkZSA9IFRSVUUsIGxlZ2VuZD1UUlVFLCB5bGltID0gYygwLDEuNSkpCgpyZXZlbnVlID0gZGF0YS5mcmFtZShjYmluZChncm93ZXJfcHJpY2VfY29uc3VtcHRpb24kWWVhciwgZ3Jvd2VyX3ByaWNlX2NvbnN1bXB0aW9uJHJldmVudWUsIHJldGFpbF9wcmljZV9jb25zdW1wdGlvbiRyZXZlbnVlKSkKY29sbmFtZXMocmV2ZW51ZSlbd2hpY2gobmFtZXMocmV2ZW51ZSkgPT0gJ1gxJyldID0gJ1llYXInCmNvbG5hbWVzKHJldmVudWUpW3doaWNoKG5hbWVzKHJldmVudWUpID09ICdYMicpXSA9ICdHcm93ZXIgUmV2ZW51ZScKY29sbmFtZXMocmV2ZW51ZSlbd2hpY2gobmFtZXMocmV2ZW51ZSkgPT0gJ1gzJyldID0gJ1JldGFpbCBSZXZlbnVlJwpyZXZlbnVlID0gZGF0YS5mcmFtZSh0KHJldmVudWUpKQpyZXZlbnVlID0gaGVhZGVyLnRydWUocmV2ZW51ZSkKb3BhciA9IHBhcihvbWEgPSBjKDEsMCwwLDgpKQpiYXJwbG90KGhlaWdodCA9IGFzLm1hdHJpeChyZXZlbnVlKSxsYXM9MiwgY2V4Lm5hbWVzID0gMC41LCBjZXguYXhpcyA9IDAuNSwgIGNvbCA9IGMoImNoYXJ0cmV1c2U0IiwiY2FkZXRibHVlMyIpLCBiZXNpZGUgPSBUUlVFLCB5YXhwPWMoMCwgbWF4KHJldmVudWUpLCA1KSkKcGFyKG9wYXIpCm9wYXIgPSBwYXIob21hID0gYygwLDAsMCwwKSwgbWFyID0gYygwLDAsMCwwKSwgbmV3ID0gVFJVRSkKbGVnZW5kKHggPSAicmlnaHQiLCBsZWdlbmQgPSByb3duYW1lcyhyZXZlbnVlKSwgZmlsbCA9IGMoImNoYXJ0cmV1c2U0IiwiY2FkZXRibHVlMyIpLCBidHkgPSAibiIsIHkuaW50ZXJzcCA9IDIpCnBhcihvcGFyKSAjIFJlc2V0IHBhcgoKCgpgYGAKCgoKCiMjIyBQbG90IGZhcm1lciBwcm9maXRzL2tnIG9mIGNvZmZlZSB0byB0aGUgcG9ldmVydHkgbOG7iW5lIChVU0QvZGF5KSBmb3IgZWFjaCBjb3VudHJ5IApgYGB7cn0KIyBQcmVwYXJlIGRhdGEKY29sbmFtZXMocG92ZXJ0eV9saW5lcylbd2hpY2gobmFtZXMocG92ZXJ0eV9saW5lcykgPT0gJ0VudGl0eScpXSA9ICdjb3VudHJ5Jwpjb3N0c19jb21wZW5fY291bnRyeSA9IGRhdGEuZnJhbWUoaW5uZXJfam9pbihjb3N0c19jb21wZW5zYXRpb24scG92ZXJ0eV9saW5lcykpCmNvc3RzX2NvbXBlbl9jb3VudHJ5WydQcm9maXRzJ10gPWNvc3RzX2NvbXBlbl9jb3VudHJ5JFgyMDExIC0gY29zdHNfY29tcGVuX2NvdW50cnkkUHJvZHVjdGlvbi5Db3N0cwpjb2xuYW1lcyhjb3N0c19jb21wZW5fY291bnRyeSlbd2hpY2gobmFtZXMoY29zdHNfY29tcGVuX2NvdW50cnkpID09ICdOYXRpb25hbC5wb3ZlcnR5LmxpbmVzLi5Kb2xsaWZmZS5hbmQuUHJ5ZHouLjIwMTYuLicpXSA9ICdQb3ZlcnR5IExpbmVzJwpgYGAKCmBgYHtyIHdhcm5pbmc9RkFMU0V9CiMgUGxvdApmaWcgPC0gcGxvdF9seSgpCmZpZyA8LSBmaWcgJT4lCiAgYWRkX3RyYWNlKAogICAgdHlwZSA9ICJpbmRpY2F0b3IiLAogICAgbW9kZSA9ICJudW1iZXIrZ2F1Z2UiLAogICAgdmFsdWUgPSBhcy5udW1lcmljKHN1YnNldChzdWJzZXQoY29zdHNfY29tcGVuX2NvdW50cnksIGNvdW50cnkgPT0gJ0NvbG9tYmlhJyksc2VsZWN0ID0gYyhQcm9maXRzKSkpLAogICAgZG9tYWluID0gbGlzdCh4ID0gYygwLjI1LCAxKSwgeSA9IGMoMC40LCAwLjYpKSwKICAgIHRpdGxlID0gbGlzdCh0ZXh0ID0gJ0NvbG9tYmlhJyksCiAgICBnYXVnZSA9IGxpc3QoCiAgICAgIHNoYXBlID0gImJ1bGxldCIsCiAgICAgIGF4aXMgPSBsaXN0KHJhbmdlID0gbGlzdChOVUxMLCA2KSksCiAgICAgIHRocmVzaG9sZCA9IGxpc3QoCiAgICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAicmVkIiwgd2lkdGggPSAyKSwKICAgICAgICB0aGlja25lc3MgPSAwLjc1LAogICAgICAgIHZhbHVlID0gYXMubnVtZXJpYyhzdWJzZXQoY29zdHNfY29tcGVuX2NvdW50cnksIGNvdW50cnkgPT0gJ0NvbG9tYmlhJylbJ1BvdmVydHkgTGluZXMnXSkpLAogICAgICBzdGVwcyA9IGxpc3QoCiAgICAgICAgbGlzdChyYW5nZSA9IGMoMCwwLjUpLCBjb2xvciA9ICJ3aGl0ZSIpLAogICAgICAgIGxpc3QocmFuZ2UgPSBjKDAuNSwyKSwgY29sb3IgPSAid2hpdGUiKSkpLAogICAgYmFyID0gbGlzdChjb2xvciA9ICJibGFjayIpKQpmaWcgPC0gZmlnICU+JQogIGFkZF90cmFjZSgKICAgIHR5cGUgPSAiaW5kaWNhdG9yIiwKICAgIG1vZGUgPSAibnVtYmVyK2dhdWdlIiwKICAgIHZhbHVlID0gYXMubnVtZXJpYyhzdWJzZXQoc3Vic2V0KGNvc3RzX2NvbXBlbl9jb3VudHJ5LCBjb3VudHJ5ID09ICdHdWF0ZW1hbGEnKSxzZWxlY3QgPSBjKFByb2ZpdHMpKSksCiAgICBkb21haW4gPSBsaXN0KHggPSBjKDAuMjUsIDEpLCB5ID0gYygwLjcsIDAuOSkpLAogICAgdGl0bGUgPSBsaXN0KHRleHQgPSAnR3VhdGVtYWxhJyksCiAgICBnYXVnZSA9IGxpc3QoCiAgICAgIHNoYXBlID0gImJ1bGxldCIsCiAgICAgIGF4aXMgPSBsaXN0KHJhbmdlID0gbGlzdChOVUxMLCA2KSksCiAgICAgIHRocmVzaG9sZCA9IGxpc3QoCiAgICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAicmVkIiwgd2lkdGggPSAyKSwKICAgICAgICB0aGlja25lc3MgPSAwLjc1LAogICAgICAgIHZhbHVlID0gYXMubnVtZXJpYyhzdWJzZXQoY29zdHNfY29tcGVuX2NvdW50cnksIGNvdW50cnkgPT0gJ0d1YXRlbWFsYScpWydQb3ZlcnR5IExpbmVzJ10pKSwKICAgICAgc3RlcHMgPSBsaXN0KAogICAgICAgIGxpc3QocmFuZ2UgPSBjKDAsMC41KSwgY29sb3IgPSAid2hpdGUiKSwKICAgICAgICBsaXN0KHJhbmdlID0gYygwLjUsMiksIGNvbG9yID0gIndoaXRlIikpKSwKICAgIGJhciA9IGxpc3QoY29sb3IgPSAiYmxhY2siKSkKZmlnIDwtIGZpZyAlPiUKICBhZGRfdHJhY2UoCiAgICB0eXBlID0gImluZGljYXRvciIsCiAgICBtb2RlID0gIm51bWJlcitnYXVnZSIsCiAgICB2YWx1ZSA9IGFzLm51bWVyaWMoc3Vic2V0KHN1YnNldChjb3N0c19jb21wZW5fY291bnRyeSwgY291bnRyeSA9PSAnRWwgU2FsdmFkb3InKSxzZWxlY3QgPSBjKFByb2ZpdHMpKSksCiAgICBkb21haW4gPSBsaXN0KHggPSBjKDAuMjUsIDEpLCB5ID0gYygwLjA4LCAwLjI1KSksCiAgICB0aXRsZSA9IGxpc3QodGV4dCA9ICdFbCBTYWx2YWRvcicpLAogICAgZ2F1Z2UgPSBsaXN0KAogICAgICBzaGFwZSA9ICJidWxsZXQiLAogICAgICBheGlzID0gbGlzdChyYW5nZSA9IGxpc3QoTlVMTCwgNikpLAogICAgICB0aHJlc2hvbGQgPSBsaXN0KAogICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gInJlZCIsIHdpZHRoID0gMiksCiAgICAgICAgdGhpY2tuZXNzID0gMC43NSwKICAgICAgICB2YWx1ZSA9IGFzLm51bWVyaWMoc3Vic2V0KGNvc3RzX2NvbXBlbl9jb3VudHJ5LCBjb3VudHJ5ID09ICdFbCBTYWx2YWRvcicpWydQb3ZlcnR5IExpbmVzJ10pKSwKICAgICAgc3RlcHMgPSBsaXN0KAogICAgICAgIGxpc3QocmFuZ2UgPSBjKDAsMC41KSwgY29sb3IgPSAid2hpdGUiKSwKICAgICAgICBsaXN0KHJhbmdlID0gYygwLjUsMiksIGNvbG9yID0gIndoaXRlIikpKSwKICAgIGJhciA9IGxpc3QoY29sb3IgPSAiYmxhY2siKSkKZmlnCgpgYGAKCgoK